<?php
/**
 * Stav autentifikacie
 * @author Tomas Srna
 * @package bakalarka
 */
class Auth extends Singleton
{ 
	/**
	 * Prihlaseny uzivatel
	 * @var $user UserModel
	 */
	protected $user = NULL;
		
	/**
	 * Konstruktor
	 * V konstruktore sa pokusime obnovit relaciu, pokial existuje
	 */
	protected function __construct()
	{
		if(!Db::hasInstance())
			return;
		
		$this->cleanUp();
		if(array_key_exists('auth_token', $_COOKIE))
		{
			$token = TokenModel::load(array('uuid' => $_COOKIE['auth_token']));
			
			// Ak neexistuje token v databaze, pravdepodobne vyprsal. Oznamime to uzivatelovi.
			if($token == NULL || $token->valid_until < time())
			{
				// Odstranime cookie, aby sme upratali
				setcookie('auth_token', NULL, time()-86400, APPBASE);
				
				// Extremne dolezite je znicit session - ak sa neznici, je to fatalna bezpecnostna chyba!!!
				session_start();
				session_destroy();
				setcookie("session_id", NULL, time()-86400, APPBASE);
				
				// Redirectneme uzivatela
				header("Location: ".APPBASE."error/inactivity");
				exit();
			}
			$this->tick($token);
			$this->user = UserModel::load(array('username' => $token->username));
		}
	}
	
	/**
	 * Vymaze dany token
	 * @param TokenModel $token
	 * @return bool Uspech
	 */
	protected function destroy(TokenModel $token)
	{
		return $token->delete();
	}
	
	/**
	 * Pri neperzistentnych tokenoch je potrebne obnovovat valid_until
	 * kvoli sposobu pocitania necinnosti.
	 * @param $token
	 * @return void
	 */
	protected function tick($token)
	{
		$token->valid_until = time() + Config::$inactivity*60;
		$token->save();
	}
	
	//---PUBLIC---
	
	/**
	 * Otestuje prihlasovacie udaje, ale v pripade uspechu neprihlasi
	 * @param string $username Meno
	 * @param string $password Heslo
	 * @return bool Spravnost kombinacie mena a hesla
	 */
	public function checkLogin($username, $password)
	{
		if(!($u = UserModel::load(array('username' => $username))) || 
			!$u->checkPassword($password))
			return false;
		return true;
	}
	
	/**
	 * Prihlasovacia funkcia
	 * @param string $username
	 * @param string $password
	 * @param bool $persistent
	 * @throws Exception
	 * @return bool Uspech prihlasenia
	 */
	public function login($username, $password, $persistent = false)
	{
		if($this->checkLogin($username, $password))
		{
			$token = TokenModel::create(array(
				'uuid'			=> ($uuid = $this->uuid()),
				'username' 		=> $username,
				'ip' 			=> $_SERVER["REMOTE_ADDR"],
				'persistent'	=> ($persistent?1:0),
				'valid_until'	=> ($persistent ?
										time() + 14*24*60*60 /* 14 dni */ :
										time() + Config::$inactivity*60)
			));
			if(!$token->save())
			{
				throw new Exception('L::unknownLoginError');
			}
			else
			{
				if($persistent)
					setcookie('auth_token', $uuid, time() + 14*24*60*60, APPBASE);
				else
					setcookie('auth_token', $uuid, NULL, APPBASE);
				
				Logger::log("L::userLoggedIn;".json_encode(
					array($_POST['username'])), 'info');
				
				return true;
			}
		}
		else 
		{
			Logger::log("L::incorrectLoginAttempt;".json_encode(
					array($_POST['username'])), 'warning');
			return false;
		}
	}
	
	/**
	 * Generator UUID
	 * @return string UUID
	 */
	function uuid($prefix = '')
	{
		$stream = md5(uniqid(mt_rand(), true));
		$uuid  = substr($stream,0,8) . '-';
		$uuid .= substr($stream,8,4) . '-';
		$uuid .= substr($stream,12,4) . '-';
		$uuid .= substr($stream,16,4) . '-';
		$uuid .= substr($stream,20,12);
		
		return $uuid;
	}
	
	/**
	 * Odhlasenie uzivatela
	 * @return bool Uspech
	 */
	public function logout()
	{
		if(!$this->isAuth())
			return false;
		
		$token = TokenModel::load(array('uuid' => $_COOKIE['auth_token']));
		$token->delete();
		
		setcookie('auth_token', NULL, time()-86400, APPBASE);
		
		// Extremne dolezite je znicit session - ak sa neznici, je to fatalna bezpecnostna chyba!!!
		session_start();
		session_destroy();
		setcookie("session_id", NULL, time()-86400, APPBASE);
		
		return true;
	}
	
	/**
	 * Vycisti stare tokeny
	 * @return bool Uspech
	 */
	public function cleanUp()
	{
		if(!Selector::select()->from(TokenModel::struct())
			->where('valid_until < ?', time())->delete())
			return false;
		return true;
	}
	
	/**
	 * Test prihlasenosti uzivatela
	 * @return bool Ci je uzivatel prihlaseny
	 */
	public function isAuth()
	{
		return ($this->user != NULL);
	}
	
	/**
	 * Vrati prihlaseneho pouzivatela
	 * @return UserModel
	 */
	public function getUser()
	{
		return $this->user;
	}
	
	/**
	 * Pozadovanie autentifikacie
	 * @return bool Ci splna kriterium
	 */
	public function requireAuth()
	{
		if($this->isAuth())
			return true;
		else
		{
			header("Location: ".APPBASE."action/login?redir=".getenv('REQUEST_URI'));
			exit();
		}
	}
}
